package cn.itcast.hotel;


import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Map;

/**
 * @author oldwine
 * @date 2022/6/18
 * @Version 1.0
 */
public class EsDocumentQueryDemo {

    private RestHighLevelClient client;

    /**
     * 高亮显示查询
     */
    @Test
    public void queryHighLighter() throws IOException {
        //TODO:1.创建请求对象,封装请求参数
        SearchRequest request = new SearchRequest("hotel");
        //1.1设置查询
        request.source().query(QueryBuilders.matchQuery("all", "如家"));
        //1.2设置高亮
        request.source().highlighter(new HighlightBuilder()
                .field("name")
                .requireFieldMatch(false)
        );

        //TODO:2.发送请求 ,获取响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //TODO: 3.解析响应结果
        SearchHits searchHits = response.getHits();
        //获取文档总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("获取文档总条数为:"+total);
        //获取文档source
        SearchHit[] hits = searchHits.getHits();
        //遍历数组
        for (SearchHit hit : hits) {
            //获取文档的json字符串
            String json = hit.getSourceAsString();
            //将json字符串封装成对象
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);

            //处理高亮
            Map<String, HighlightField> fields = hit.getHighlightFields();
            if ( !CollectionUtils.isEmpty(fields)){
                //获取高亮字段结果
                HighlightField name = fields.get("name");
                if (name != null){
                    String nameStr = name.getFragments()[0].string();
                    hotelDoc.setName(nameStr);
                }
            }
            System.out.println("hotelDoc = " + hotelDoc);
        }

    }

    /**
     * 分页和排序查询   from size sort
     */
    @Test
    public void queryPageAndOrder() throws IOException {
        //TODO:1.创建请求对象,封装请求数据
        SearchRequest request = new SearchRequest("hotel");
        //1.1 设置查询
        request.source().query(QueryBuilders.matchAllQuery());
        //1.2 设置分页
        request.source().from(0).size(5);
        //1.3设置排序
        request.source().sort("price", SortOrder.ASC);

        //TODO:2.发送请求,获取响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //TODO:3.解析响应结果
        SearchHits searchHits = response.getHits();
        //获取文档总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("获取文档总条数为:" + total);
        //获取文档source
        SearchHit[] hits = searchHits.getHits();
        //遍历数组
        for (SearchHit hit : hits) {
            //获取每条文档字Json符串
            String json = hit.getSourceAsString();
            //将json字符串封装成对象
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            System.out.println("hotelDoc = " + hotelDoc);
        }

    }

    /**
     * 布尔查询: must must_not  should filter
     */
    @Test
    public void queryBool() throws IOException {
        //TODO: 1.创建请求对象,封装请求参数
        //1.1 创建请求对象
        SearchRequest request = new SearchRequest("hotel");
        //1.2 封装请求参数
        //创建bool查询类型对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //添加词条查询
        boolQuery.must(QueryBuilders.termQuery("city", "杭州"));
        //添加范围查询
        boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
        request.source().query(boolQuery);

        //TODO:2.发送请求,获取响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //TODO:3.解析响应结果
        SearchHits searchHits = response.getHits();
        //3.1 获取文档总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("总共获取" + total + "条文档数据");
        //3.2 获取文档数组对象
        SearchHit[] hits = searchHits.getHits();
        //遍历数组
        for (SearchHit hit : hits) {
            //获取文档的json字符串
            String json = hit.getSourceAsString();
            //将json字符串封装成对象
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            System.out.println(hotelDoc);
        }
    }

    /**
     * 精准查询 : term range
     */
    @Test
    public void queryPrecise() throws IOException {
        //TODO:1.创建请求对象 封装请求参数
        //1.1 获取请求对象
        SearchRequest request = new SearchRequest("hotel");
        //1.2 封装请求参数
        //词条查询
       /* request.source()
                .query(QueryBuilders.termQuery("city","上海"));*/
        //范围查询
        request.source()
                .query(QueryBuilders.rangeQuery("price").gte(100).lte(150));

        //TODO:2.发送请求,获取响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //TODO:3.解析响应结果
        SearchHits searchHits = response.getHits();
        //3.1 获取文档总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共获取文档" + total + "条");
        //3.2 获取文档source
        SearchHit[] hits = searchHits.getHits();
        //遍历数组 获取每一条文档
        for (SearchHit hit : hits) {
            //获取每一条文档json数据
            String json = hit.getSourceAsString();
            //将json数据封装成对象
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            System.out.println(hotelDoc);
        }
    }

    /**
     * 全文检索 : match multi_match
     */
    @Test
    public void queryMatch() throws IOException {
        //TODO: 1.创建请求对象,封装请求参数
        //1.1创建请求对象
        SearchRequest request = new SearchRequest("hotel");
        //1.2 封装请求参数
        //单字段查询
//        request.source()
//                .query(QueryBuilders.matchQuery("all","如家"));
        //多字段查询
        request.source().
                query(QueryBuilders.multiMatchQuery("如家", "name", "business"));

        //TODO:2发送请求,获取响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //TODO:3.解析响应结果
        SearchHits searchHits = response.getHits();
        //3.1 获取文档总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到" + total + "条数据");
        //3.2 获取文档数组
        SearchHit[] hits = searchHits.getHits();
        //遍历数组
        for (SearchHit hit : hits) {
            //获取文档source
            String json = hit.getSourceAsString();
            //将JSon数据封装成对象
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            System.out.println(hotelDoc);
        }
    }

    /**
     * 查询所有 : match_all
     * 1.创建请求参数 ,封装请求参数
     * 2.发送请求,获得响应结果
     * 3.解析响应结果
     */
    @Test
    public void queryAll() throws IOException {
        //TODO:1.创建请求对象,封装请求参数
        //1.1 创建请求对象
        SearchRequest request = new SearchRequest("hotel");
        //1.2 封装请求参数
        request.source()
                .query(QueryBuilders.matchAllQuery());

        //TODO:2.发送请求,获得响应结果
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //TODO:3.解析响应结果
        SearchHits searchHits = response.getHits();
        //3.1 获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到" + total + "条数据");
        //3.2 获取文档数组
        SearchHit[] hits = searchHits.getHits();
        //3.3 遍历数组
        for (SearchHit hit : hits) {
            //获取文档source
            String json = hit.getSourceAsString();
            //将Json转成对象
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            System.out.println(hotelDoc);
        }

    }


    /**
     * 创建ES客户端
     */
    @BeforeEach
    public void init() {
        client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://122.112.171.22:9200")
        ));
    }

    /**
     * 关闭ES客户端
     */
    @AfterEach
    public void close() {
        if (client != null) {
            try {
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}